#include "Map.h"
#include "Player.h"
#include "Vistor.h"

Map::Map(void) : 
	m_flags(MF_INVALID),
	m_cells(NULL),
	m_cell_x_num(0),
	m_cell_y_num(0)
{
}

Map::~Map(void)
{
}

void Map::create(uint32 guid, const std::string& name, uint32 w, uint32 h)
{
	GameObject::create(guid,name);
	m_cell_x_num = w / (uint32)CELL_SIZE;
	m_cell_y_num = h / (uint32)CELL_SIZE;

	LOG_INFO << "create map guid: " << guid << " name:" << name << " w:" << w << " h:" << h
		<< "m_cell_x_num: " << m_cell_x_num << "m_cell_y_num: " << m_cell_y_num;


	m_cells = new Cell*[m_cell_x_num];

	for(int i=0; i < m_cell_x_num; ++i)
	{
		m_cells[i] = new Cell[m_cell_y_num];
	}
}

CellPair Map::computeCell(float x, float y)
{
	return CellPair(x/CELL_SIZE, y/CELL_SIZE);
}

Cell* Map::getCell(const CellPair& cell)
{
	return &m_cells[cell.x][cell.y];
}

void Map::addToMap(WorldObject* obj)
{
	LOG_DEBUG << "addToMap: " << obj->getName();
	ASSERT(obj);

	float x = obj->getX();
	float y = obj->getY();
	CellPair cell = computeCell(x,y);

	getCell(cell)->addObject(obj);
	obj->setInWorld(true);

	ArrayBuffer* msg = new ArrayBuffer;

	BuilldPropertyVistor build_properties(*msg);
	obj->visitAllProperties(build_properties);

	obj->resetUpdatedMask();
	broadcastMessageToSet(obj,msg);

// 	obj->getEvent(ET_POSITION_CHANGED)->subscibe(
// 		boost::bind(&Map::handlePositionChanged,this,_1));
}

void Map::removeFromMap(WorldObject* obj)
{
	ASSERT(obj->getMapID() == getGUID());
	ASSERT(obj->isInWorld());

	float x = obj->getX();
	float y = obj->getY();
	CellPair cell = computeCell(x,y);
	getCell(cell)->removeObject(obj);
}

void Map::handlePositionChanged(EventParams& params)
{

}

void Map::broadcastMessage(WorldObject* obj, ArrayBuffer* msg)
{
	visitPlayers(visitAll(boost::bind(&Player::sendMessage,_1,msg)));
}

void Map::broadcastMessageToSet(WorldObject* obj, ArrayBuffer* msg)
{
	float x = obj->getX();
	float y = obj->getY();
	CellPair cell = computeCell(x,y);

	visitPlayersInSet(cell.x,cell.y, visitAll(boost::bind(&Player::sendMessage,_1,msg)));

}

void Map::reLocation(WorldObject* obj, float x, float y)
{
	CellPair cell = computeCell(obj->getX(),obj->getY());
	CellPair new_cell = computeCell(x,y);
	if (cell == new_cell)
		return;

	obj->setX(x);
	obj->setY(y);

	ArrayBuffer* msg = new ArrayBuffer;

	BuilldPropertyVistor build_properties(*msg);
	obj->visitUpdatedProperties(build_properties);

	obj->resetUpdatedMask();
	broadcastMessageToSet(obj,msg);
}